Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Crystal::PointerLinkedList instead of Deque in Mutex #15330

Conversation

ysbaddaden
Copy link
Contributor

Follows WaitGroup that uses a linked list instead of a deque to store the waiting fibers.

The flat array doesn't have much impact on performance: we only reach the head or the tail once to dequeue/dequeue one fiber at a time. This however spares a number of GC allocations since the Deque has to be allocated plus its buffer that will have to be reallocated sometimes (and will only ever grow, never shrink).

Extracts the undocumented Fiber::Waiting struct from WaitGroup that acts as the node in the linked list.

Renames @lock to @spin since the former was a bit confusing, for example with @lock_count that counts the number of reentrancy.

The flat array also doesn't have much impact since it's never traversed:
we only reach the head or the tail once (to dequeue or dequeue one).

This spares a number of GC allocations since the Deque needs to be
allocated and also a buffer that will have to be reallocated sometimes
(and will only ever grow).
@BlobCodes
Copy link
Contributor

This PR seems to remove the need for @queue_count since PointerLinkedList#empty? should be just as fast

@ysbaddaden
Copy link
Contributor Author

Well Deque#empty? would have been just the same.

What we really need is to know whether there's a waiter and it must be atomic, so unlock can safely spare acquiring the spinlock when there are no waiters.

Now, we don't need to count: it could be a simple flag on the spinlock value, set when #lock acquires the spinlock and unset when #unlock releases it and there are no waiters (this is what the nsync library does).

@straight-shoota straight-shoota changed the title Use Crystal::PointerLinkedList instead of Deque in Mutex Use Crystal::PointerLinkedList instead of Deque in Mutex Jan 13, 2025
src/fiber/waiting.cr Outdated Show resolved Hide resolved
src/fiber/waiting.cr Outdated Show resolved Hide resolved
src/mutex.cr Show resolved Hide resolved
@straight-shoota straight-shoota added this to the 1.16.0 milestone Jan 14, 2025
@straight-shoota straight-shoota merged commit 5b20837 into crystal-lang:master Jan 15, 2025
70 checks passed
@ysbaddaden ysbaddaden deleted the refactor/use-pointer-linked-list-in-mutex branch January 15, 2025 13:00
straight-shoota pushed a commit that referenced this pull request Jan 20, 2025
Changes the `flag` that keeps track of initialization status of constants and class variables to have 3 states instead of 2. The third one indicates that the value is currently being initialized and allows detecting recursion.
Previously we used an array to keep track of values being currently initialized. This array is now unnecessary.

The signature of `__crystal_once` changes: it now takes an Int8 (i8) instead of Bool (i1) and drops the once `state` pointer which isn't needed anymore. So `__crystal_once_init` no longer initializes a state pointer and returns nil.

Also introduces a fast path for the (very likely) scenario that the variable is already initialized which doesn't need a mutex.
Also introduces an LLVM optimization that instructs LLVM to optimize away repeated calls to `__crystal_once` for the same initializer.

Requires a new compiler build to benefit from the improvement. The legacy versions of `__crystal_once` and `__crystal_once_init` are still supported by both the stdlib and the compiler to keep both forward & backward compatibility (1.15 and below can build 1.16+ and 1.16+ can build 1.15 and below).

A follow-up could leverage `ReferenceStorage` and `.unsafe_construct` to inline the `Mutex` instead of allocating in the GC heap. Along with #15330 then `__crystal_once_init` could become allocation free, which could prove useful for such a core/low level feature.

Co-authored-by: David Keller <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

3 participants